package top.lyf1210.yuwenpicturebackend.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.context.annotation.Lazy;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;
import top.lyf1210.yuwenpicturebackend.enums.SpaceLevelEnum;
import top.lyf1210.yuwenpicturebackend.enums.SpaceRoleEnum;
import top.lyf1210.yuwenpicturebackend.enums.SpaceTypeEnum;
import top.lyf1210.yuwenpicturebackend.exception.BusinessException;
import top.lyf1210.yuwenpicturebackend.exception.ErrorCode;
import top.lyf1210.yuwenpicturebackend.exception.ThrowUtils;
import top.lyf1210.yuwenpicturebackend.model.Picture;
import top.lyf1210.yuwenpicturebackend.model.Space;
import top.lyf1210.yuwenpicturebackend.model.SpaceUser;
import top.lyf1210.yuwenpicturebackend.model.User;
import top.lyf1210.yuwenpicturebackend.model.dto.space.SpaceAddRequest;
import top.lyf1210.yuwenpicturebackend.model.dto.space.SpaceQueryRequest;
import top.lyf1210.yuwenpicturebackend.model.vo.picture.PictureVO;
import top.lyf1210.yuwenpicturebackend.model.vo.space.SpaceVO;
import top.lyf1210.yuwenpicturebackend.model.vo.user.UserVO;
import top.lyf1210.yuwenpicturebackend.service.PictureService;
import top.lyf1210.yuwenpicturebackend.service.SpaceService;
import top.lyf1210.yuwenpicturebackend.mapper.SpaceMapper;
import org.springframework.stereotype.Service;
import top.lyf1210.yuwenpicturebackend.service.SpaceUserService;
import top.lyf1210.yuwenpicturebackend.service.UserService;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import static top.lyf1210.yuwenpicturebackend.constant.OrderConstant.ASC;

/**
* @author 钰玟
* @description 针对表【t_space(空间)】的数据库操作Service实现
* @createDate 2025-05-13 14:13:12
*/
@Service
public class SpaceServiceImpl extends ServiceImpl<SpaceMapper, Space>
    implements SpaceService{
    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    private UserService userService;
    @Resource
    @Lazy
    private PictureService pictureService;
    @Resource
    @Lazy
    private SpaceUserService spaceUserService;
    /**
     * 校验空间信息
     * @param space 空间
     * @param isAdd 是否是  新增
     */
    @Override
    public void validSpace(Space space, boolean isAdd) {

        //1.判断空间 是否为空
        ThrowUtils.throwIf(space == null, ErrorCode.PARAMS_ERROR);
        //2.  获取相关信息
        //2.1 空间名称
        String spaceName = space.getSpaceName();
        // 2.2 空间级别
        Integer spaceLevel = space.getSpaceLevel();
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(spaceLevel);
        //2.3 空间类型
        Integer spaceType = space.getSpaceType();
        SpaceTypeEnum spaceTypeEnum = SpaceTypeEnum.getEnumByValue(spaceType);

        //判断是否是新增
        if(isAdd){
            // 则名称不能为空
            if(StrUtil.isBlank(spaceName)){
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间名称不能为空");
            }
            //级别
            if(spaceLevelEnum == null){
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间级别错误");
            }
            //空间类型
            if (spaceType == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间类型不能为空");
            }
        }
        //是 编辑
            // 空间名称不能为空
            if(StrUtil.isNotBlank(spaceName) && spaceName.length()>30){
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间名称过长");
            }
            if(spaceLevelEnum == null && spaceLevel!=null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间级别错误");
            }
            // 修改数据时，如果要改空间级别
            if (spaceType != null && spaceTypeEnum == null) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "空间类型不存在");
            }


    }

    /**
     * 根据空间级别填充空间相关信息
     * @param space
     */
    @Override
    public void fillSpaceWithSpaceLevel(Space space) {
        //1. 获取空间级别
        SpaceLevelEnum spaceLevelEnum = SpaceLevelEnum.getEnumByValue(space.getSpaceLevel());
        if(spaceLevelEnum != null){
            Long maxCount = space.getMaxCount();
            if(maxCount == null){
                //设置最大数量
                space.setMaxCount(spaceLevelEnum.getMaxCount());
            }
            Long maxSize = space.getMaxSize();
            if(maxSize==null){
                //设置最大空间
                space.setMaxSize(spaceLevelEnum.getMaxSize());
            }
        }
    }

    /**
     * 添加空间
     * @param spaceAddRequest 添加空间参数
     * @param loginUser 对应操作的用户
     */
    @Override
    public long addSpace(SpaceAddRequest spaceAddRequest, User loginUser) {
        ThrowUtils.throwIf(spaceAddRequest == null, ErrorCode.PARAMS_ERROR);

        if(StrUtil.isBlank(spaceAddRequest.getSpaceName())){
            spaceAddRequest.setSpaceName("默认空间");
        }
        //空间级别
        if(spaceAddRequest.getSpaceLevel() == null){
            spaceAddRequest.setSpaceLevel(SpaceLevelEnum.COMMON.getValue());
        }
        //空间类型
        if (spaceAddRequest.getSpaceType() == null) {
            spaceAddRequest.setSpaceType(SpaceTypeEnum.PRIVATE.getValue());
        }
        //在此处将实体类和 DTO 进行转换
        Space space = new Space();
        BeanUtil.copyProperties(spaceAddRequest, space);

        //自动填充
        this.fillSpaceWithSpaceLevel(space);
        //数据校验
        this.validSpace(space,true);
        //设置用户id
        space.setUserId(loginUser.getId());
        //判断权限
        if(spaceAddRequest.getSpaceLevel()!=SpaceLevelEnum.COMMON.getValue() && userService.isAdmin(loginUser)){
            throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"无权限创建此类型的空间");
        }
        String lock = String.valueOf(space.getUserId()).intern();
        synchronized (lock){
            Long newSpaceId = transactionTemplate.execute(action -> {
                //如果不是管理员，则只能创建一个空间
                if(!userService.isAdmin(loginUser)){
                    boolean exists = this.lambdaQuery()
                            .eq(Space::getUserId, space.getUserId())
                            .eq(Space::getSpaceType, spaceAddRequest.getSpaceType())
                            .exists();
                    ThrowUtils.throwIf(exists,ErrorCode.OPERATION_ERROR,"每个用户每类空间只能创建一个");
                }


                //
                // 写入数据库
                boolean result = this.save(space);
                ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR);
                // 如果是团队空间，关联新增团队成员记录
                if (SpaceTypeEnum.TEAM.getValue() == spaceAddRequest.getSpaceType()) {
                    SpaceUser spaceUser = new SpaceUser();
                    spaceUser.setSpaceId(space.getId());
                    spaceUser.setUserId(loginUser.getId());
                    spaceUser.setSpaceRole(SpaceRoleEnum.ADMIN.getValue());
                    result = spaceUserService.save(spaceUser);
                    ThrowUtils.throwIf(!result, ErrorCode.OPERATION_ERROR, "创建团队成员记录失败");
                }
                // 返回新写入的数据 id
                return space.getId();
            });
            return Optional.ofNullable(newSpaceId).orElse(-1L);
        }
    }

    /**
     *删除空间时，关联删除空间内的图片
     * @param id id
     */
    @Override
    public void deleteSpace(Long id) {
        //删除空间的同时删除空间下的图片 使用TransactionTemplate
        ThrowUtils.throwIf(id<0,ErrorCode.PARAMS_ERROR);
        transactionTemplate.execute(status -> {
            //1. 删除空间
            boolean isSpace = this.removeById(id);
            //2. 删除空间下的图片
            //2.1 查询空间下的图片
            List<Picture> pictureList = pictureService.lambdaQuery().eq(Picture::getSpaceId, id).list();
            //2.2批量删除 (一次性)
            boolean isPictures = pictureService.removeBatchByIds(pictureList);
            ThrowUtils.throwIf(!isSpace,ErrorCode.OPERATION_ERROR);
            return isSpace && isPictures;
        });
    }

    /**
     * 获取查询包装类
     * @param spaceQueryRequest 查询条件
     * @return
     */
    @Override
    public QueryWrapper<Space> getQueryWrapper(SpaceQueryRequest spaceQueryRequest) {
        //1.创建查询条件
        QueryWrapper<Space> queryWrapper = new QueryWrapper<>();
        //判断条件是否为空
        if (spaceQueryRequest == null) {
            return queryWrapper;
        }
        //2. 提取条件 == 空间名称，空间级别
        String spaceName = spaceQueryRequest.getSpaceName();
        Integer spaceLevel = spaceQueryRequest.getSpaceLevel();
        String sortField = spaceQueryRequest.getSortField();
        String sortOrder = spaceQueryRequest.getSortOrder();
        Integer spaceType = spaceQueryRequest.getSpaceType();



        //3.封装条件
        queryWrapper.eq(StrUtil.isNotBlank(spaceName), "spaceName", spaceName);
        queryWrapper.eq(ObjUtil.isNotNull(spaceLevel), "spaceLevel", spaceLevel);
        queryWrapper.eq(ObjUtil.isNotEmpty(spaceType), "spaceType", spaceType);
        queryWrapper.orderBy(StrUtil.isNotBlank(sortField), sortOrder.equals(ASC), sortField);
        return queryWrapper;
    }

    @Override
    public Page<SpaceVO> getPictureVOPage(Page<Space> page, HttpServletRequest request) {
        List<Space> spaceList = page.getRecords();
        Page<SpaceVO> spaceVOPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        if(CollUtil.isEmpty(spaceList)){
            return spaceVOPage;
        }
        List<SpaceVO> pictureVOList = spaceList.stream().map(SpaceVO::objToVo).collect(Collectors.toList());
        //1.关联查询用户信息
        Set<Long> userIdSet = spaceList.stream().map(Space::getUserId).collect(Collectors.toSet());
        Map<Long,List<User>> userIdUserListMap = userService.listByIds(userIdSet).stream()
                .collect(Collectors.groupingBy(User::getId));

        //2.填充信息
        pictureVOList.forEach(pictureVO -> {
            Long userId = pictureVO.getUserId();
            User user = null;
            if(userIdUserListMap.containsKey(userId)){
                user = userIdUserListMap.get(userId).get(0);
            }
            pictureVO.setUser(userService.getUserVO(user));
        });
        spaceVOPage.setRecords(pictureVOList);
        return spaceVOPage;
    }

    /**
     * 检查空间权限
     * @param spaceById
     * @param loginUser
     */
    @Override
    public void checkSpaceAuth(Space spaceById, User loginUser) {
        //1.获取空间De所有者
        Long userId = spaceById.getUserId();
         if(userId.equals(loginUser.getId())||  userService.isAdmin(loginUser)){
             return;
         }else{
             throw new BusinessException(ErrorCode.NO_AUTH_ERROR,"无权限访问");
         }

    }

    @Override
    public SpaceVO getSpaceVO(Space space, HttpServletRequest request) {
        if(space == null){
            return null;
        }
        SpaceVO spaceVO = new SpaceVO();
        BeanUtil.copyProperties(space,spaceVO);
        //获取用户信息
        Long userId = userService.getLoginUser(request).getId();
        if(userId!=null&&userId>0){
            User user = userService.getById(userId);
            UserVO userVO = userService.getUserVO(user);
            spaceVO.setUser(userVO);
            spaceVO.setUserId(userId);
        }
        return spaceVO;
    }

}




